package com.ardf.listener;

import com.ardf.entity.*;
import com.ardf.entity.dto.AthleteTeamDto;
import com.ardf.entity.dto.CardDto;
import com.ardf.entity.dto.CardSearchAllDto;
import com.ardf.service.*;
import com.ardf.util.PrintGrade;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import org.apache.xmlbeans.impl.soap.Detail;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.core.Local;
import org.springframework.web.socket.WebSocketSession;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class GradePortListener implements SerialPortDataListener {

    private CardWebSocketService webSocketService;
    private ICardService cardService;

    private IDetailsService detailsService;
    private IGradeService gradeService;
    private IAthleteTeamService teamService;
    private IBatchService batchService;
    private WebSocketSession session;
    private Competition competition;
    private String project;
    private String portName;
    private Long projectId;
    private Long competitionId;
    private Boolean isRelay;




    private int GetTen(int num1, int num2) {
        return (num1 / 16) * 16 * 16 * 16 + (num1 % 16) * 16 * 16 + num2;
    }

    private Long GetTPNumber(int[] intArray) {
        double TpNumber = 0;
        for (int i = 0; i < intArray.length; i++) {
            TpNumber += Math.pow(16, 7 - i * 2) * (intArray[i] / 16) + Math.pow(16, 7 - i * 2 - 1) * (intArray[i] % 16);

        }
        return (long) TpNumber;
    }

    //通过websocket打开监听设备的时候绑定session返回给前端数据
    public GradePortListener(CardWebSocketService webSocketService, String portName, WebSocketSession session, ICardService cardService, IGradeService gradeService, IDetailsService detailsService, IAthleteTeamService teamService,IBatchService batchService, Long projectId, boolean isRelay,Long competitionId,Competition competition,String project) {
        this.webSocketService = webSocketService;
        this.cardService = cardService;
        this.gradeService = gradeService;
        this.detailsService = detailsService;
        this.teamService=teamService;
        this.isRelay = isRelay;
        this.session = session;
        this.projectId = projectId;
        this.portName=portName;
        this.competition=competition;
        this.project=project;
        this.batchService=batchService;
        this.competitionId=competitionId;
    }

    @Override
    public int getListeningEvents() {

        return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
    }

    @Override
    public void serialEvent(SerialPortEvent event) {
        boolean flag = true;
        SerialPort port = event.getSerialPort();  //获取当前的com口
        this.webSocketService.sendMessageToUser(this.projectId, "请放置指卡");


        if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {//如果此时没有数据进来则退出监听器
            this.webSocketService.sendMessageToUser(this.projectId, "读卡中......");
            while (port.bytesAvailable() != 0) {
                String msg = "该选手并未参与该场比赛！！！";
                //创建打印对象
                Print print=new Print();

                try {
                    Thread.sleep(600);

                    byte[] newData = new byte[port.bytesAvailable()];//会返回字符数
                    int[] intArray = new int[port.bytesAvailable()];
                    int i = 0;
                    int numRead = port.readBytes(newData, newData.length); //数据长度
                    for (byte data : newData) {
                        System.out.print((data & 0xFF) + " ");
                        intArray[i] = (data & 0xFF);
                        i++;
                    }

                    //获取到TP卡号
                    String TPCard = "TP" + GetTPNumber(Arrays.copyOfRange(intArray, 14, 18));
                    //获取有效站数
                    int validNum = intArray[34];
                    print.setCount(validNum);
                    //整个路线
                    List<Details> datailsList = new ArrayList<>();
                    //路线
                    List<String> stations = new ArrayList<>();
                    //时间
                    List<String> times=new ArrayList<>();
                    //次序
                    List<String> sequences= new ArrayList<>();
                    //接力选手集合
                    List<String> names=new ArrayList<>();
                    DateTimeFormatter formatter=DateTimeFormatter.ofPattern("HH:mm:ss");

                    LocalTime startTime = LocalTime.MIN;
                    LocalTime endTime = LocalTime.MIN;
                    String route = "";


                    Card card = this.cardService.selectByTp(TPCard,this.projectId);

                    if(card==null){
                        ReplaceCard replaceCard=this.cardService.selectReplaceCardByComIdAndNum(this.competitionId,TPCard);
                        if(replaceCard!= null){
                            Card card1=new Card();
                            card1.setAthleteId(replaceCard.getAthleteId());

                            card=card1;
                            System.out.println(card+"999");
                        }
                    }

                    if (card != null) {
                        print.setCompetitionName(this.competition.getName());
                        print.setCompetitionOrganization(this.competition.getOrganization());
                        print.setProject(this.project);
                        print.setDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
                        //根据选手Id和项目id得到成绩
                        Grade grade;
                        Batch batch = null;
                        AthleteTeam athleteTeam = null;
                        List<AthleteTeamDto> athleteTeamDtos=null;
                        if(this.isRelay){
                            //根据指卡号获取接力团队的id
                            athleteTeam = this.teamService.selectTeamByAthId(card.getAthleteId());
                            grade = this.gradeService.selectByProIdAndTId(this.projectId, athleteTeam.getTeamId());
                            //根据项目id和选手id查询当前选手的出发次序
                            batch=this.batchService.selectBatchByPIdAndAthId(this.projectId,card.getAthleteId());
                            //根据接力队伍id查询队伍信息
                            athleteTeamDtos=this.teamService.selectPrintAthleteByTeamId(athleteTeam.getTeamId(),this.projectId);
                            for (AthleteTeamDto dto:athleteTeamDtos){
                                names.add(dto.getAthleteName());
                            }
                            print.setAthleteNames(names); //接力赛的选手信息
                            print.setTeamName(athleteTeamDtos.get(0).getTeamName());
                            print.setGroup(athleteTeamDtos.get(0).getGroupName());

                        }else{
                            //个人赛
                            grade = this.gradeService.selectByProIdAndAthId(this.projectId, card.getAthleteId());
                            Print athPrint = this.cardService.selectPrintByAthId(card.getAthleteId());
                            print.setGroup(athPrint.getGroup());
                            print.setCard(athPrint.getCard());
                            print.setAthleteName(athPrint.getAthleteName());
                            print.setNumber(athPrint.getNumber());
                        }
                        //保存指卡中的选手路线
                        if (grade != null) {
                            if (grade.getRoute() == null) {  //未录入
                                int index = 0;
                                if (isRelay) {
                                    List<Details> details = this.detailsService.selectByGId(grade.getId());
                                    index = details.size();
                                }

                                for (int j = 35; (j + 4) < numRead; j += 5, index++) { //绑定打卡线路
                                    LocalTime time = LocalTime.of(intArray[j + 1], intArray[j + 2], intArray[j + 3], intArray[j + 4]);
                                    LocalDateTime dtime = LocalDateTime.of(LocalDate.now(), time);
                                    Details details = new Details(TPCard, index, intArray[j], dtime, grade.getId());
                                    datailsList.add(details);
                                    times.add(time.format(formatter));
                                    sequences.add(String.valueOf(index));

                                    if(j==35){
                                        if(intArray[j] == 0){
                                            route = route + "起点";
                                            stations.add("起点");
                                            startTime = time;
                                        }else if(intArray[j] >=1 && intArray[j] <= 10){
                                            route = route + intArray[j];
                                            stations.add(String.valueOf(intArray[j]));

                                        }else if(intArray[j] >=11 && intArray[j] <= 15){
                                            route = route + "F" + intArray[j]%10;
                                            stations.add("F" + intArray[j]%10);
                                        }else if(intArray[j] == 19){
                                            route = route + "S";
                                            stations.add("S");
                                        }else if(intArray[j] == 20){
                                            route = route + "MO";
                                            stations.add("MO");
                                        } else if(intArray[j] == 99){
                                            route = route + "终点";
                                            stations.add("终点");
                                        }
                                    }
                                    else if(j == numRead - 7){
                                        if(j != 35){
                                            route = route + "-";
                                        }
                                        if(intArray[j] == 0){
                                            route = route + "起点";
                                            stations.add("起点");
                                        }else if(intArray[j] >=1 && intArray[j] <= 10){
                                            route = route + intArray[j];
                                            stations.add(String.valueOf(intArray[j]));
                                        }else if(intArray[j] >=11 && intArray[j] <= 15){
                                            route = route + "F" + intArray[j]%10;
                                            stations.add("F" + intArray[j]%10);
                                        }else if(intArray[j] == 19){
                                            route = route + "S";
                                            stations.add("S");
                                        }else if(intArray[j] == 20){
                                            route = route + "MO";
                                            stations.add("MO");
                                        }else if(intArray[j] == 99){
                                            route = route + "终点";
                                            stations.add("终点");
                                            endTime = time;
                                        }
                                    }else{

                                        if(intArray[j] >=1 && intArray[j] <= 10){
                                            route = route + "-" + intArray[j];
                                            stations.add(String.valueOf(intArray[j]));
                                        }else if(intArray[j] >=11 && intArray[j] <= 15){
                                            route = route + "-F" + intArray[j]%10;
                                            stations.add("F" + intArray[j]%10);
                                        }else if(intArray[j] ==19){
                                            route = route + "-S";
                                            stations.add("S");
                                        }else if(intArray[j] ==20){
                                            route = route + "-MO";
                                            stations.add("MO");
                                        }
                                    }


                                }
                                LocalTime rtime=LocalTime.MIN;
                                long totalSeconds;
                                int nanos;
                                int hours;
                                int minutes;
                                int seconds;
                                if(!startTime.equals(LocalTime.MIN) && !endTime.equals(LocalTime.MIN) ){
                                    Duration duration = Duration.between(startTime, endTime);
                                    totalSeconds = duration.getSeconds();
                                    nanos = duration.getNano();
                                    hours = (int) totalSeconds / 3600;
                                    minutes = (int) (totalSeconds % 3600) / 60;
                                    seconds = (int) totalSeconds % 60;
                                    System.out.println(route);
                                    rtime = LocalTime.of(hours, minutes, seconds, nanos);
                                }else{
                                    rtime=LocalTime.MIN;
                                }

                                grade.setRoute(route);
                                grade.setTime(rtime);
                                print.setTime(rtime.format(formatter)); //保存耗时
                                grade.setStatus((byte) 1);

                                //保存详细路线
                                this.detailsService.saveAll(datailsList);
                                //更新路线和耗时
                                this.gradeService.updateById(grade);

//                                if (this.isRelay && batch.getSequence() == 3) {
//                                    //根据成绩id查询打卡路线详情
//                                    List<Details> details = this.detailsService.selectByGId(grade.getId());
//                                    String teamRoute = "";
//                                    stations.clear();
//                                    times.clear();
//                                    sequences.clear();
//                                    details.size();
//                                    for (Details detail : details) {
//                                        if(detail.getOrder()!=0){
//                                            teamRoute=teamRoute+"-";
//                                        }
//                                        times.add(detail.getClockTime().toLocalTime().format(formatter));
//                                        sequences.add(String.valueOf(detail.getOrder()));
//                                        if (detail.getStationNumber() == 0) {
//                                            teamRoute = teamRoute + "起点";
//                                            stations.add("起点");
//                                            detail.getClockTime();
//                                        }else if (detail.getStationNumber() >= 1 && detail.getStationNumber() <= 10) {
//                                            teamRoute = teamRoute + detail.getStationNumber();
//                                            stations.add(String.valueOf(detail.getStationNumber()));
//                                        }else if (detail.getStationNumber() >= 11 && detail.getStationNumber() <= 15) {
//                                            teamRoute = teamRoute + "F" + detail.getStationNumber()%10;
//                                            stations.add(String.valueOf(detail.getStationNumber()));
//                                        }else if (detail.getStationNumber() == 19) {
//                                            teamRoute = teamRoute + "S";
//                                            stations.add("S");
//                                        }else if (detail.getStationNumber() == 20) {
//                                            teamRoute = teamRoute + "MO";
//                                            stations.add("MO");
//                                        } else if (detail.getStationNumber() == 99) {
//                                            teamRoute = teamRoute + "终点";
//                                            stations.add("终点");
//                                        }
//                                    }
//                                    if(details.get(0).getStationNumber()==0 && details.get(details.size() - 1).getStationNumber()==99){
//                                        Duration teamDuration = Duration.between(details.get(0).getClockTime(), details.get(details.size() - 1).getClockTime());
//                                        totalSeconds = teamDuration.getSeconds();
//                                        nanos = teamDuration.getNano();
//                                        hours = (int) totalSeconds / 3600;
//                                        minutes = (int) (totalSeconds % 3600) / 60;
//                                        seconds = (int) totalSeconds % 60;
//                                        rtime = LocalTime.of(hours, minutes, seconds, nanos);
//                                    }else{
//                                        rtime=LocalTime.MIN;
//                                    }
//
//                                    grade.setAthleteId(card.getAthleteId());
//                                    grade.setRoute(teamRoute);
//                                    grade.setTime(rtime);
//                                    grade.setStatus((byte) 1);
//                                    this.gradeService.updateById(grade);
//
//                                    print.setTime(rtime.format(formatter)); //保存耗时
//                                }

                                print.setRoutes(stations);    //保存打卡路线
                                print.setTimeList(times);
                                print.setSequences(sequences);

                                ExecutorService executor = Executors.newFixedThreadPool(2);
                                executor.submit(() -> {
                                    PrintGrade printGrade = new PrintGrade(print, this.webSocketService, this.projectId, this.isRelay);
                                    printGrade.printGrade();


                                });

                                executor.shutdown();



                                if (!this.isRelay) {

                                    //发送消息给前台，更新打卡详情部分
                                    this.webSocketService.sendMessageToUser(this.projectId, "成绩id:" + grade.getId());


                                } else {//发送消息给前台，更新打卡详情部分
                                    this.webSocketService.sendMessageToUser(this.projectId, "成绩id:" + grade.getId() + "接力队伍id:" + athleteTeam.getTeamId());
                                }


                                    Thread.sleep(1000);
                                    this.webSocketService.sendMessageToUser(this.projectId, "读卡结束......");
                                    Thread.sleep(1000);
                                    this.webSocketService.sendMessageToUser(this.projectId, "请放置指卡");



                            } else { //已录入
                                msg = "请勿重复录入!!!";
                                Thread.sleep(700);
                                this.webSocketService.sendMessageToUser(this.projectId, msg);
                                Thread.sleep(700);
                                this.webSocketService.sendMessageToUser(this.projectId, "请放置指卡");
                            }
                        }
                    }else{
                        Thread.sleep(500);
                        this.webSocketService.sendMessageToUser(this.projectId, msg);
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        }
    }

}
